﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static System.Windows.Forms.LinkLabel;

namespace OxyPlotDemo
{
    /// <summary>
    /// CircularPointsControl.xaml 的交互逻辑
    /// </summary>
    public partial class CircularPointsControl : UserControl
    {
        private double centerX = 0, centerY = 0, radius = 100;

        private int? draggedPointIndex { get; set; } = null;

        public List<Line> lines { get; set; } = new List<Line>();
        public List<Ellipse> ellipses { get; set; } = new List<Ellipse>();
        public List<TextBlock> textBlocks { get; set; } = new List<TextBlock>();

        // 外部的角度集合
        public static readonly DependencyProperty AnglesProperty =
            DependencyProperty.Register(nameof(Angles), typeof(ObservableCollection<double>), typeof(CircularPointsControl),
                new PropertyMetadata(null, OnAnglesChanged));

        public ObservableCollection<double> Angles
        {
            get => (ObservableCollection<double>)GetValue(AnglesProperty) ?? new ObservableCollection<double>();
            set => SetValue(AnglesProperty, value);
        }

        // 绑定外部的是否等分模式
        public static readonly DependencyProperty IsEqualSpacingModeProperty =
            DependencyProperty.Register(nameof(IsEqualSpacingMode), typeof(bool), typeof(CircularPointsControl),
                new PropertyMetadata(true, OnIsEqualSpacingModeChanged));

        public bool IsEqualSpacingMode
        {
            get => (bool)(GetValue(IsEqualSpacingModeProperty) ?? true);
            set => SetValue(IsEqualSpacingModeProperty, value);
        }

        // 绑定外部的等分数量
        public static readonly DependencyProperty EqualDivisionsProperty =
            DependencyProperty.Register(nameof(EqualDivisions), typeof(int), typeof(CircularPointsControl),
                new PropertyMetadata(4, OnEqualDivisionsChanged));

        public int EqualDivisions
        {
            get => (int)(GetValue(EqualDivisionsProperty) ?? 4);
            set => SetValue(EqualDivisionsProperty, value);
        }

        // 绑定外部的偏移角度
        public static readonly DependencyProperty OffsetAngleProperty =
            DependencyProperty.Register(nameof(OffsetAngle), typeof(double), typeof(CircularPointsControl),
                new PropertyMetadata(0.0, OnOffsetAngleChanged));

        public double OffsetAngle
        {
            get => (double)(GetValue(OffsetAngleProperty) ?? 0.0);
            set => SetValue(OffsetAngleProperty, value);
        }

        private static void OnAnglesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (CircularPointsControl)d;
            
            control.RefreshCircle();
        }

        private static void OnIsEqualSpacingModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (CircularPointsControl)d;
            
            control.UpdateAngles();
        }

        private static void OnEqualDivisionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (CircularPointsControl)d;
            control.UpdateAngles();
        }



        private static void OnOffsetAngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (CircularPointsControl)d;
            control.UpdateAngles();
        }

        public CircularPointsControl()
        {
            InitializeComponent();
            SetDefaultValues();
        }

        private void SetDefaultValues()
        {
            if (Angles == null)
                Angles = new ObservableCollection<double>();

            if (GetValue(IsEqualSpacingModeProperty) == null)
                IsEqualSpacingMode = true;

            if (GetValue(EqualDivisionsProperty) == null)
                EqualDivisions = 4;

            if (GetValue(OffsetAngleProperty) == null)
                OffsetAngle = 0.0;
        }

        private void RefreshCircle()
        {
            DrawingCanvas.Children.Clear();
            DrawCircle(centerX, centerY, radius);
            DrawPointsOnCircle();
        }

        private void DrawCircle(double centerX, double centerY, double radius)
        {
            Ellipse circle = new Ellipse
            {
                Width = radius * 2,
                Height = radius * 2,
                Stroke = Brushes.Gray,
                StrokeThickness = 3,
                Name = ""
            };
            Canvas.SetLeft(circle, centerX - radius);
            Canvas.SetTop(circle, centerY - radius);
            DrawingCanvas.Children.Add(circle);
            Line xAxis = new Line
            {
                X1 = centerX - radius - 10,
                Y1 = centerY,
                X2 = centerX + radius + 10,
                Y2 = centerY,
                Stroke = Brushes.Black,
                StrokeThickness = 2
            };
            DrawingCanvas.Children.Add(xAxis);

            Line yAxis = new Line
            {
                X1 = centerX,
                Y1 = centerY - radius - 10,
                X2 = centerX,
                Y2 = centerY + radius + 10,
                Stroke = Brushes.Black,
                StrokeThickness = 2
            };
            DrawingCanvas.Children.Add(yAxis);
        }
        private void DrawPointsOnCircle()
        {
            lines.Clear();
            ellipses.Clear();
            textBlocks.Clear();
            var i = 0;
            foreach (var angle in Angles)
            {
                double radian = (angle - 90) * Math.PI / 180;
                double x = centerX + radius * Math.Cos(radian);
                double y = centerY + radius * Math.Sin(radian);
                double x1 = centerX;
                double y1 = centerY - radius;
                // 创建并添加线
                Line line = new Line
                {
                    X1 = centerX,
                    Y1 = centerY,
                    X2 = x1,
                    Y2 = y1,
                    Stroke = Brushes.Black,
                    StrokeThickness = 1,
                };

                lines.Add(line);

                DrawingCanvas.Children.Add(line);

                // 创建并添加点
                Ellipse point = new Ellipse
                {
                    Width = 8,
                    Height = 8,
                    Fill = Brushes.Red,
                };
                Canvas.SetLeft(point, x1 - point.Width / 2);
                Canvas.SetTop(point, y1 - point.Height / 2);
                ellipses.Add(point);
                DrawingCanvas.Children.Add(point);

                // 创建并添加文本
                TextBlock angleText = new TextBlock
                {
                    Text = $"{angle}°",
                    Foreground = Brushes.Black,
                };
                Canvas.SetLeft(angleText, x1);
                Canvas.SetTop(angleText, y1 - 20);
                textBlocks.Add(angleText);
                DrawingCanvas.Children.Add(angleText);

                line.RenderTransform = new RotateTransform(angle, centerX, centerY);
                point.RenderTransform = new RotateTransform(angle, -x1 + point.Width / 2, -y1 + point.Height / 2);
                angleText.RenderTransform = new RotateTransform(angle, x1, -y1 + 20);
                i++;
            }
        }
        private void UpdatePointsOnCircle(int roundedAngle, int? draggedPointIndex)
        {
            if (!draggedPointIndex.HasValue) return;
            int index = draggedPointIndex.Value;
            // 更新线的位置
            Line line = lines[index];
            // 更新点的位置
            Ellipse point = ellipses[index];
            // 更新文本的位置和内容
            TextBlock angleText = textBlocks[index];
            angleText.Text = $"{roundedAngle}°";

            // 更新旋转变换的角度
            RotateTransform rotateTransformLine = line.RenderTransform as RotateTransform;
            if (rotateTransformLine != null)
            {
                rotateTransformLine.Angle = roundedAngle;  // 更新线的旋转角度
            }

            RotateTransform rotateTransformPoint = point.RenderTransform as RotateTransform;
            if (rotateTransformPoint != null)
            {
                rotateTransformPoint.Angle = roundedAngle;  // 更新点的旋转角度
            }

            RotateTransform rotateTransformText = angleText.RenderTransform as RotateTransform;
            if (rotateTransformText != null)
            {
                rotateTransformText.Angle = roundedAngle;  // 更新文本的旋转角度
            }


        }
        private void UpdateAngles()
        {
            draggedPointIndex = null;

            if (!IsEqualSpacingMode) 
            {
                OffsetAngle = 0;
                
            }
            
            if (int.TryParse(EqualDivisions.ToString(), out int divisions) && double.TryParse(OffsetAngle.ToString(), out double offset))
            {
                Angles.Clear();
                for (int i = 0; i < divisions; i++)
                {
                    double angle = offset + (i * 360.0 / divisions);
                    angle = angle % 360;
                    angle = Math.Round(angle, 5);
                    Angles.Add(angle);
                }
                RefreshCircle();
            }
        }

        private int? GetNearestPointIndex(Point mousePosition)
        {
            double minDistance = double.MaxValue;
            int? nearestIndex = null;

            for (int i = 0; i < Angles.Count; i++)
            {
                double radian = (Angles[i] - 90) * Math.PI / 180;
                double x = centerX + radius * Math.Cos(radian);
                double y = centerY + radius * Math.Sin(radian);

                double distance = Math.Sqrt(Math.Pow(mousePosition.X - x, 2) + Math.Pow(mousePosition.Y - y, 2));
                if (distance < minDistance && distance < 10)
                {
                    minDistance = distance;
                    nearestIndex = i;
                }
            }
            return nearestIndex;
        }

        private void DrawingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (draggedPointIndex.HasValue)
            {
                ellipses[draggedPointIndex.Value].Fill = Brushes.Red;
                lines[draggedPointIndex.Value].Stroke = Brushes.Black;
                draggedPointIndex = null;

            }

            if (!draggedPointIndex.HasValue && e.LeftButton == MouseButtonState.Pressed)
            {
                Point mousePosition = e.GetPosition(DrawingCanvas);
                draggedPointIndex = GetNearestPointIndex(mousePosition);
                if (draggedPointIndex != null)
                {
                    AngleSlider.Value = Angles[draggedPointIndex.Value];
                    ellipses[draggedPointIndex.Value].Fill = Brushes.Blue;
                    lines[draggedPointIndex.Value].Stroke = Brushes.Blue;
                }
            }
        }

        private DateTime lastUpdate = DateTime.MinValue;
        private void DrawingCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (!IsEqualSpacingMode && e.LeftButton == MouseButtonState.Pressed && draggedPointIndex.HasValue)
            {

                var now = DateTime.Now;
                if ((now - lastUpdate).TotalMilliseconds < 100)
                    return;
                double angle = CalAngle(new Point(0, 0), e.GetPosition(DrawingCanvas));

                if (angle < 0) angle += 360;
                int roundedAngle = (int)Math.Round(angle);
                Angles[draggedPointIndex.Value] = roundedAngle;
                AngleSlider.Value = roundedAngle;
                UpdatePointsOnCircle(roundedAngle, draggedPointIndex);
                lastUpdate = DateTime.Now;
            }
        }

        public static double CalAngle(Point center, Point p) => Math.Atan2(p.Y - center.Y, p.X - center.X) * 180 / Math.PI + 90;

        private void AngleSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (draggedPointIndex == null) return;
            int roundedAngle = (int)AngleSlider.Value;
            Angles[draggedPointIndex.Value] = roundedAngle;
            UpdatePointsOnCircle(roundedAngle, draggedPointIndex);
        }
    }
}
